package cn.itcast.demo;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.junit.Test;
import org.wltea.analyzer.lucene.IKAnalyzer;

import java.io.File;
import java.io.IOException;

/**
 * @author 虎哥
 */
public class LuceneSearchTest {

    @Test
    public void testSearch() throws IOException, ParseException {
        // 2.构建搜索条件
        // 查询解析器
        QueryParser queryParser = new QueryParser("title", new IKAnalyzer());
        // 对用户输入的内容分词，得到查询条件
        Query query = queryParser.parse("拉斯");

        search(query);
    }

    @Test
    public void testTermQuery() throws IOException {
        // 构建词条查询
        TermQuery termQuery = new TermQuery(new Term("id", "1"));
        // 搜索和渲染
        search(termQuery);
    }

    @Test
    public void testFuzzyQuery() throws IOException {
        // 构建词条查询
        FuzzyQuery query = new FuzzyQuery(new Term("title", "fscevool"), 5);
        // 搜索和渲染
        search(query);
    }

    @Test
    public void testNumericRangeQuery() throws IOException {
        // 构建词条查询
        NumericRangeQuery<Long> query = NumericRangeQuery.newLongRange("id", 1L, 3L, false, true);
        // 搜索和渲染
        search(query);
    }

    @Test
    public void testBooleanQuery() throws IOException {
        // 构建词条查询
        NumericRangeQuery<Long> query1 = NumericRangeQuery.newLongRange("id", 1L, 3L, true, true);
        NumericRangeQuery<Long> query2 = NumericRangeQuery.newLongRange("id", 2L, 4L, true, true);

        // 布尔查询，不需要条件，把其它查询用逻辑关系连接
        BooleanQuery query = new BooleanQuery();
        query.add(query1, BooleanClause.Occur.MUST_NOT);
        query.add(query2, BooleanClause.Occur.SHOULD);


        // 搜索和渲染
        search(query);
    }



    private void search(Query query) throws IOException {
        // 1.构建搜索工具
        // 读取流
        IndexReader reader = DirectoryReader.open(FSDirectory.open(new File("C:\\lesson\\heima78\\indexDir")));
        // 搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        // 3.开始搜索，应该得到包含词条的文档的编号数组,但是要返回多个信息，所以封装为对象，包含了总条数、数组,
        // 参数：搜索条件， 搜索的条数
        TopDocs topDocs = searcher.search(query, 5);

        // 4.解析结果
        // 4.1.总条数
        System.out.println(String.format("本次搜索共得到%d条数据",topDocs.totalHits));
        // 4.2.获取scoreDoc数组, scoreDoc包含分数、文档编号
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        // 4.3.遍历
        for (int i = 0; i < scoreDocs.length; i++) {
            ScoreDoc scoreDoc = scoreDocs[i];
            // 取编号
            int docID = scoreDoc.doc;
            // 根据编号寻找文档
            Document doc = searcher.doc(docID);
            // 获取字段
            System.out.println("id：" + doc.get("id"));
            System.out.println("title：" + doc.get("title"));
            // 取得分
            System.out.println("得分：" + scoreDoc.score);
        }
    }

    @Test
    public void testHighlighter() throws Exception {
        // 目录对象
        Directory directory = FSDirectory.open(new File("C:\\lesson\\heima78\\indexDir"));
        // 创建读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 创建搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        QueryParser parser = new QueryParser("title", new IKAnalyzer());
        Query query = parser.parse("谷歌地图");

        // 格式化器
        Formatter formatter = new SimpleHTMLFormatter("<em>", "</em>");
        QueryScorer scorer = new QueryScorer(query);
        // 准备高亮工具
        Highlighter highlighter = new Highlighter(formatter, scorer);

        // 搜索
        TopDocs topDocs = searcher.search(query, 10);
        System.out.println("本次搜索共" + topDocs.totalHits + "条数据");

        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
        for (ScoreDoc scoreDoc : scoreDocs) {
            // 获取文档编号
            int docID = scoreDoc.doc;
            Document doc = searcher.doc(docID);
            System.out.println("id: " + doc.get("id"));

            String title = doc.get("title");
            // 用高亮工具处理普通的查询结果,参数：分词器，要高亮的字段的名称，高亮字段的原始值
            title = highlighter.getBestFragment(new IKAnalyzer(), "title", title);

            System.out.println("title: " + title);
            // 获取文档的得分
            System.out.println("得分：" + scoreDoc.score);
        }

    }

    @Test
    public void testSort() throws Exception {
        int page = 1;
        int size = 10;
        int start = (page - 1) * size;
        int end = page * size;

        // 目录对象
        Directory directory = FSDirectory.open(new File("C:\\lesson\\heima78\\indexDir"));
        // 创建读取工具
        IndexReader reader = DirectoryReader.open(directory);
        // 创建搜索工具
        IndexSearcher searcher = new IndexSearcher(reader);

        QueryParser parser = new QueryParser("title", new IKAnalyzer());
        Query query = parser.parse("谷歌地图");

        // 搜索
        TopDocs topDocs = searcher.search(query, end, new Sort(new SortField("id", SortField.Type.STRING, true)));
        System.out.println("本次搜索共" + topDocs.totalHits + "条数据");

        ScoreDoc[] scoreDocs = topDocs.scoreDocs;

        for (ScoreDoc scoreDoc : scoreDocs) {
            // 获取文档编号
            int docID = scoreDoc.doc;
            Document doc = searcher.doc(docID);
            System.out.println("id: " + doc.get("id"));

            String title = doc.get("title");
            System.out.println("title: " + title);
            // 获取文档的得分
            System.out.println("得分：" + scoreDoc.score);
        }

    }
}
